#include "task.hpp"

void login_user(const HttpRequest& req, HttpResponse& resp)
{
    if (req._param.find("username") != req._param.end())
    {
        Json::Value message;
        Account* account_ptr = Account::get_instance();
        if (account_ptr->login_user(req._param.find("username")->second, req._param.find("password")->second) == false)
        {
            message["success"] = false;
            message["message"] = "账号密码错误";
#ifdef __TEST_DEBUG__
            log(Log::Debug, "login fault, user id: %s, json: %s", req._param.find("username")->second.c_str(), Json::FastWriter().write(message).c_str());
#endif
        }
        else
        {         
            message["success"] = true;
            message["message"] = "登录成功";
            message["expire"] = 60 * 60 * 24;
            Json::Value data;
            data["id"] = req._param.find("username")->second;
            message["data"] = data;
#ifdef __TEST_DEBUG__
            log(Log::Debug, "login success, user id: %s, json: %s", req._param.find("username")->second.c_str(), Json::FastWriter().write(message).c_str());
#endif
        }
        resp.serializer(Json::FastWriter().write(message), ".json");
    }
}

void reset_password(const HttpRequest& req, HttpResponse& resp)
{
    Json::Value message;
    if (req._param.find("username") != req._param.end())
    {
        Account* account_ptr = Account::get_instance();
        if (account_ptr->find_user(req._param.find("username")->second) == nullptr)
        {
            message["success"] = false;
            message["message"] = "账号不存在，请注册";
            resp.serializer(Json::FastWriter().write(message), ".json");
        }
        else
        {
            if (account_ptr->modify_user(req._param.find("username")->second, AccountUnit::MODIFY_PASSWORD, req._param.find("password")->second))
            {
                message["success"] = true;
                message["message"] = "操作成功";
            }
            else
            {
                message["success"] = false;
                message["message"] = "账号不存在，请创建账号";  
            }
            resp.serializer(Json::FastWriter().write(message), ".json");
        }
    }
}

void register_user(const HttpRequest& req, HttpResponse& resp)
{
    Json::Value message;
    if (req._param.find("username") != req._param.end())
    {
        Account* account_ptr = Account::get_instance();
        if (account_ptr->insert_user({req._param.find("username")->second, req._param.find("password")->second}))
        {
            message["success"] = true;
            message["message"] = "操作成功";
        }
        else
        {
            message["success"] = false;
            message["message"] = "该账号已存在/服务器繁忙";
        }
        resp.serializer(Json::FastWriter().write(message), ".json");
    }
}

std::string getStatus(int battery)
{
    if (battery >= 1000) return "停止充电";
    if (battery == 100) return "已充满";
    if (battery >= 95) return "即将充满";
    if (battery <= 20) return "低电量";
    return "充电中";
}

void user_info(const HttpRequest& req, HttpResponse& resp)
{
    Json::Value message;
    if (req._param.find("id") != req._param.end())
    {
        Account* account_ptr = Account::get_instance();
        if (account_ptr->find_user(req._param.find("id")->second) == nullptr)
        {
            message["success"] = false;
            message["message"] = "未找到用户";
            resp.serializer(Json::FastWriter().write(message), ".json");
            return;
        }

        const std::unique_ptr<AccountUnit> unit_ptr(AccountUnit::open(req._param.find("id")->second));

        if (unit_ptr != nullptr)
        {
            message["success"] = true;
            message["message"] = "获取用户数据成功";
            Json::Value data;
            data["id"] = unit_ptr->_user_id;
            data["money"] = ((double)unit_ptr->_money) / 100;
            
            Json::Value devices(Json::arrayValue);
            for (auto e : unit_ptr->_charge_list)
            {
                Json::Value device;
                device["deviceId"] = e.first;
                device["battery"] = e.second;
                device["status"] = getStatus(e.second);
                devices.append(std::move(device));
            }

            data["devices"] = devices;
            message["data"] = data;
        }
        else
        {
            message["success"] = false;
            message["message"] = "服务器繁忙";
        }
        log(Log::Info, "user_info json: %s", Json::FastWriter().write(message).c_str());
        resp.serializer(Json::FastWriter().write(message), ".json");
    }
}

void http_task(std::string& inbuffer, std::string& outbuffer)
{
    static std::mutex s_mtx;
    
    HttpRequest req;
    if (!req.deserializer(inbuffer))
        return;
#ifdef __TEST_DEBUG__
    req.print();
#endif

    HttpResponse resp;
    if (req._api.empty())
        resp.serializer(req);
    else
    {
        std::lock_guard<std::mutex> lg(s_mtx);
        if (req._api == "login")
            login_user(req, resp);
        else if (req._api == "reset_password")
            reset_password(req, resp);
        else if (req._api == "register")
            register_user(req, resp);
        else if (req._api == "user_info")
            user_info(req, resp);
    }
    outbuffer.swap(resp.response);
}

void get_charge_info(const std::string& inbuffer, std::string& outbuffer)
{
    // 接收数据
    std::string id;
    int spend = -1;
    int state = -1;
    std::pair<std::string, int> device;
    device.second = -1;

    std::stringstream ss(inbuffer);
    ss >> state >> id >> device.first >> device.second >> spend;
    if (state == -1 || id.empty() || device.first.empty() || device.second == -1 || spend == -1)
        return;
#ifdef __TEST_DEBUG__
    log(Log::Debug, "state: %d, id: %s, device id: %s, battery: %d, spend: %d", state, id.c_str(), device.first.c_str(), device.second, spend);
#endif
    
    // 发送数据
    int flag = 0;
    int money = 0;

    Account* account_ptr = Account::get_instance();
    if (account_ptr->find_user(id) == nullptr)
        flag = 1;   // 找不到用户
    else
    {
        const std::unique_ptr<AccountUnit> unit_ptr(AccountUnit::open(id));
        if (unit_ptr != nullptr)
        {
            // 用户充电
            if (state == 0)
            {
                if (spend > unit_ptr->_money || spend <= 0)
                    flag = 2;   // 钱不够
                else
                {
                    unit_ptr->_money -= spend;
                    unit_ptr->_charge_list[device.first] = device.second;
                }
            }
            // 获取用户电量
            else if (state == 1)
            {
                unit_ptr->_charge_list[device.first] = device.second;
            }
            // 用户结束充电
            else if (state == 2)
            {
                if (unit_ptr->_charge_list.find(device.first) != unit_ptr->_charge_list.end())
                {
                    unit_ptr->_money += spend;
                    unit_ptr->_charge_list.erase(device.first);
                }
                else
                    flag = 1;
            }
            // 用户暂停充电
            else if (state == 3)
            {
                if (unit_ptr->_charge_list.find(device.first) != unit_ptr->_charge_list.end())
                {
                    unit_ptr->_money += spend;
                    unit_ptr->_charge_list[device.first] += 1000;
                }
                else
                    flag = 1;
            }
            else if (state == 4)
            {
                if (spend > unit_ptr->_money || spend < 0)
                    flag = 2;   // 钱不够
            }
            money = unit_ptr->_money;
            account_ptr->save_user(*unit_ptr);
        }
    }
    char buffer[32] = { 0 };
#ifdef __TEST_DEBUG__
    log(Log::Debug, "flag: %d, money: %d", flag, money);
#endif
    snprintf(buffer, sizeof(buffer), "recv %d %d", flag, money);
    outbuffer = buffer;
}

void device_task(std::string& inbuffer, std::string& outbuffer)
{
    size_t pos = inbuffer.find("\r\n");
    if (pos != std::string::npos)
    {
        log(Log::Info, "read form device: %s", inbuffer.c_str());
        if (strncmp(inbuffer.c_str(), "ping", 4) == 0)
            outbuffer = "cmd=1&res=1";
        else
            get_charge_info(inbuffer, outbuffer);
        log(Log::Info, "send to device: %s", outbuffer.c_str());
        inbuffer.erase(0, pos + 2);
    }
}
